#include "logger.h"
#include "common.h"
#include "drv_uart.h"

#include "math_util.h"
#include <stdarg.h>

#define dbg_uart	uart1

#define ESC "\033"

#define CBLK ESC"[30m"
#define CRED ESC"[31m"
#define CGRN ESC"[32m"
#define CYEL ESC"[33m"
#define CBLU ESC"[34m"
#define CMAG ESC"[35m"
#define CCYN ESC"[36m"
#define CWHT ESC"[37m"

#define CHIR ESC"[1;31m"
#define CHIG ESC"[1;32m"
#define CHIY ESC"[1;33m"
#define CHIB ESC"[1;34m"
#define CHIM ESC"[1;35m"
#define CHIC ESC"[1;36m"
#define CHIW ESC"[1;37m"

#define CHBRED ESC"[41;1m"
#define CHBGRN ESC"[42;1m"
#define CHBYEL ESC"[43;1m"
#define CHBBLU ESC"[44;1m"
#define CHBMAG ESC"[45;1m"
#define CHBCYN ESC"[46;1m"
#define CHBWHT ESC"[47;1m"

#define CBBLK ESC"[40m"
#define CBRED ESC"[41m"
#define CBGRN ESC"[42m"
#define CBYEL ESC"[43m"
#define CBBLU ESC"[44m"
#define CBMAG ESC"[45m"
#define CBCYN ESC"[46m"

#define NOR ESC"[0m"

static const char *LEVEL_PREFIX[] =
{
    CMAG,		//!< fatal
    CHIR,		//!< error
    CHIY,		//!< warning
    CHIG,		//!< info
    CBLU,		//!< debug
    NOR,		//!< verbose
};

void logger_output(int level, const char *tag, int line_num, const char *fmt, ...)
{
    static char buf[LOG_BUF_SIZE];

    va_list args;
    int idx = 0;
    uint32_t tick = sys_get_time();

    level = MATH_MAX(0, level);
    level = MATH_MIN(level, ARRAY_SIZE(LEVEL_PREFIX) - 1);
    idx += snprintf(buf + idx, sizeof(buf) - idx, "[%lu.%03lu] [%s:%d] %s",
            tick / 1000, tick % 1000, tag, line_num, LEVEL_PREFIX[level]);

    va_start(args, fmt);
    idx += vsnprintf(buf + idx, sizeof(buf) - idx, fmt, args);
    va_end(args);

    idx += snprintf(buf + idx, sizeof(buf) - idx, "\r\n" NOR);

    drv_uart_send(&dbg_uart, buf, idx);
}

void logger_array(const void *buf, int size)
{
    char tmp[16];
    int len;

    for (int i = 0; i < size; i++)
    {
        if (i % LOG_HEX_WIDTH == 0 && i != 0)
        {
            drv_uart_send_str(&dbg_uart, "\r\n");
        }
        len = snprintf(tmp, sizeof(tmp), "%02x ", ((uint8_t*) buf)[i]);
        drv_uart_send(&dbg_uart, tmp, len);
    }
    drv_uart_send_str(&dbg_uart, "\r\n");
}

int _write(int fd, char *str, int len)
{
    if (fd == stdout->_file)
    {
        drv_uart_send(&dbg_uart, str, len);
    }

    return len;
}

void __assert_func (const char *file, int line, const char *func, const char *ex)
{
    printf("(%s) assertion failed at file:%s. function:%s, line number:%d\r\n",
            ex, file, func, line);
    while(1);
}

